#include <SD_MMC.h>
#include "ESP32USBMSC.h"
#include <SPIFFS.h>
#include <driver/sdmmc_host.h>
#include <driver/sdmmc_defs.h>
#include <driver/gpio.h>
#include <OneButton.h>
#include <Preferences.h>

Preferences prefs;

// SD_MMC 引脚配置
gpio_num_t clk = GPIO_NUM_40;
gpio_num_t cmd = GPIO_NUM_39;
gpio_num_t d0 = GPIO_NUM_41;
gpio_num_t d1 = GPIO_NUM_42;
gpio_num_t d2 = GPIO_NUM_48;
gpio_num_t d3 = GPIO_NUM_38;
bool onebit = false;

// 状态变量
bool isMounted = false;
bool needFileTest = false;
uint32_t lastUnmountTime = 0;
const uint32_t UNMOUNT_DELAY = 1000; // 1秒延迟

// OneButton 按键对象，GPIO0
OneButton button(0, true);

// 文件读写测试函数
void testFileOperations()
{
    const char *testFileName = "/test.txt";
    const char *testContent = "Hello ESP32! This is a test file.";

    Serial.println("\n开始文件操作测试...");

    // 检查 SD 卡状态
    if (!SD_MMC.cardSize())
    {
        Serial.println("错误: SD 卡未就绪!");
        return;
    }

    // 1. 创建并写入文件
    Serial.println("1. 创建测试文件...");
    File testFile = SD_MMC.open(testFileName, FILE_WRITE);
    if (!testFile)
    {
        Serial.println("创建文件失败!");
        return;
    }

    size_t bytesWritten = testFile.print(testContent);
    testFile.close();
    Serial.printf("写入 %d 字节到文件\n", bytesWritten);

    // 等待文件系统同步
    delay(100);

    // 2. 读取文件内容
    Serial.println("\n2. 读取文件内容...");
    testFile = SD_MMC.open(testFileName, FILE_READ);
    if (!testFile)
    {
        Serial.println("打开文件失败!");
        return;
    }

    if (testFile.available())
    {
        String content = testFile.readString();
        testFile.close();
        Serial.printf("文件内容: %s\n", content.c_str());
    }
    else
    {
        Serial.println("文件为空!");
        testFile.close();
    }

    // 等待文件系统同步
    delay(100);

    // 3. 删除文件
    Serial.println("\n3. 删除测试文件...");
    if (SD_MMC.exists(testFileName))
    {
        if (SD_MMC.remove(testFileName))
        {
            Serial.println("文件删除成功");
        }
        else
        {
            Serial.println("文件删除失败!");
        }
    }
    else
    {
        Serial.println("文件不存在!");
    }

    Serial.println("文件操作测试完成\n");
}

// 列出文件函数
void listFiles(fs::FS &fs, const char *dirname, uint8_t levels)
{
    Serial.printf("列出目录: %s\n", dirname);

    File root = fs.open(dirname);
    if (!root)
    {
        Serial.println("无法打开目录");
        return;
    }
    if (!root.isDirectory())
    {
        Serial.println("不是目录");
        return;
    }

    File file = root.openNextFile();
    while (file)
    {
        if (file.isDirectory())
        {
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if (levels)
            {
                listFiles(fs, file.name(), levels - 1);
            }
        }
        else
        {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("  SIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}

// USB 事件回调函数
void myUsbEventHandler(int32_t event_id, void *event_data)
{
    switch (event_id)
    {
    case ARDUINO_USB_STARTED_EVENT:
        Serial.println("USB 连接");
        break;
    case ARDUINO_USB_STOPPED_EVENT:
        Serial.println("USB 断开");
        break;
    case ARDUINO_USB_SUSPEND_EVENT:
        Serial.printf("USB 挂起: remote_wakeup_en: %u\n", ((arduino_usb_event_data_t *)event_data)->suspend.remote_wakeup_en);
        break;
    case ARDUINO_USB_RESUME_EVENT:
        Serial.println("USB 恢复");
        break;
    default:
        break;
    }
}

// 挂载状态回调函数
void myMountHandler(bool mounted)
{
    if (mounted)
    {
        Serial.println("----------------------------------------");
        Serial.println("U盘已挂载 - 可以开始访问文件");
        Serial.println("----------------------------------------");
        isMounted = true;
        needFileTest = false;
    }
    else
    {
        Serial.println("----------------------------------------");
        Serial.println("U盘已卸载 - 请安全移除设备");
        Serial.println("----------------------------------------");
        isMounted = false;
        needFileTest = true;
        lastUnmountTime = millis();
    }
}

// 按键回调函数，切换 USB MSC 挂载/断开
void toggleUsbMsc()
{
    usbMsc.setAutoMountFlag(!usbMsc.getAutoMountFlag());
    ESP.restart();
}

void setup()
{
    Serial.begin(115200);
    Serial.println("Starting...");

    // 记录开始时间
    uint32_t startTime = millis();

    // 配置 SDMMC 主机参数
    sdmmc_host_t host = SDMMC_HOST_DEFAULT();
    host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
    host.flags = SDMMC_HOST_FLAG_1BIT | SDMMC_HOST_FLAG_4BIT | SDMMC_HOST_FLAG_8BIT | SDMMC_HOST_FLAG_DDR;
    host.slot = SDMMC_HOST_SLOT_1;

    // 配置 SDMMC 总线参数
    sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
    slot_config.width = 4;
    slot_config.clk = clk;
    slot_config.cmd = cmd;
    slot_config.d0 = d0;
    slot_config.d1 = d1;
    slot_config.d2 = d2;
    slot_config.d3 = d3;

    // 初始化 SD_MMC，挂载 SD 卡
    Serial.println("Mounting SDcard...");
    SD_MMC.setPins((int)clk, (int)cmd, (int)d0, (int)d1, (int)d2, (int)d3);

    // 尝试不同的初始化策略
    uint32_t initTime = millis();
    bool initSuccess = false;
    uint32_t freq = SDMMC_FREQ_HIGHSPEED;
    bool formatIfMountFailed = false; // 默认不格式化

    // 第一次尝试：使用最高频率，不格式化
    Serial.println("尝试快速初始化...");
    initSuccess = SD_MMC.begin("/sdcard", onebit, formatIfMountFailed, freq);

    // 如果失败，尝试降低频率
    if (!initSuccess)
    {
        Serial.println("快速初始化失败，尝试降低频率...");
        freq = SDMMC_FREQ_DEFAULT;
        while (!initSuccess && freq >= SDMMC_FREQ_DEFAULT)
        {
            Serial.printf("尝试初始化频率: %u kHz\n", freq);
            initSuccess = SD_MMC.begin("/sdcard", onebit, formatIfMountFailed, freq);
            if (!initSuccess)
            {
                freq = freq / 2; // 降低频率重试
                delay(100);      // 等待一段时间再试
            }
        }
    }

    // 如果还是失败，尝试格式化
    if (!initSuccess)
    {
        Serial.println("标准初始化失败，尝试格式化...");
        formatIfMountFailed = true;
        initSuccess = SD_MMC.begin("/sdcard", onebit, formatIfMountFailed, freq);
    }

    if (!initSuccess)
    {
        Serial.println("SD 卡初始化失败");
        return;
    }

    // 计算初始化时间
    uint32_t endTime = millis();
    uint32_t totalTime = endTime - startTime;
    uint32_t cardInitTime = endTime - initTime;

    // 获取并打印 SD 卡信息
    uint64_t cardSize = SD_MMC.cardSize();
    uint32_t sectorSize = SD_MMC.sectorSize();
    uint32_t numSectors = SD_MMC.numSectors();

    Serial.println("\nSD卡详细信息:");
    Serial.println("----------------------------------------");
    Serial.printf("总容量: %llu MB\n", cardSize / (1024 * 1024));
    Serial.printf("扇区大小: %u bytes\n", sectorSize);
    Serial.printf("扇区数量: %u\n", numSectors);
    Serial.printf("初始化频率: %u kHz\n", freq);
    Serial.printf("初始化时间: %u ms\n", cardInitTime);
    Serial.printf("总启动时间: %u ms\n", totalTime);
    Serial.printf("初始化模式: %s\n", formatIfMountFailed ? "格式化模式" : "快速模式");

    // 测试读写速度
    Serial.println("\n测试读写速度...");
    const char *testFile = "/speed_test.txt";
    const int testSize = 1024 * 1024; // 1MB
    uint8_t *buffer = (uint8_t *)malloc(testSize);
    if (buffer)
    {
        // 填充测试数据
        for (int i = 0; i < testSize; i++)
        {
            buffer[i] = i & 0xFF;
        }

        // 连续写入测试
        Serial.println("\n1. 连续写入测试 (1MB)...");
        uint32_t writeStart = millis();
        File file = SD_MMC.open(testFile, FILE_WRITE);
        if (file)
        {
            size_t written = file.write(buffer, testSize);
            file.close();
            uint32_t writeTime = millis() - writeStart;
            float writeSpeed = (written * 1000.0f) / (writeTime * 1024.0f); // KB/s
            Serial.printf("连续写入速度: %.2f KB/s\n", writeSpeed);
        }

        // 连续读取测试
        Serial.println("\n2. 连续读取测试 (1MB)...");
        uint32_t readStart = millis();
        file = SD_MMC.open(testFile, FILE_READ);
        if (file)
        {
            size_t read = file.read(buffer, testSize);
            file.close();
            uint32_t readTime = millis() - readStart;
            float readSpeed = (read * 1000.0f) / (readTime * 1024.0f); // KB/s
            Serial.printf("连续读取速度: %.2f KB/s\n", readSpeed);
        }

        // 随机读写测试
        Serial.println("\n3. 随机读写测试...");
        const int numOperations = 100;
        const int blockSize = 4096; // 4KB
        uint32_t totalRandomWriteTime = 0;
        uint32_t totalRandomReadTime = 0;

        // 随机写入测试
        file = SD_MMC.open(testFile, FILE_WRITE);
        if (file)
        {
            for (int i = 0; i < numOperations; i++)
            {
                uint32_t pos = random(testSize - blockSize);
                file.seek(pos);
                uint32_t start = millis();
                file.write(buffer + pos, blockSize);
                totalRandomWriteTime += millis() - start;
            }
            file.close();
            float avgRandomWriteTime = totalRandomWriteTime / (float)numOperations;
            Serial.printf("平均随机写入时间: %.2f ms/4KB\n", avgRandomWriteTime);
        }

        // 随机读取测试
        file = SD_MMC.open(testFile, FILE_READ);
        if (file)
        {
            for (int i = 0; i < numOperations; i++)
            {
                uint32_t pos = random(testSize - blockSize);
                file.seek(pos);
                uint32_t start = millis();
                file.read(buffer, blockSize);
                totalRandomReadTime += millis() - start;
            }
            file.close();
            float avgRandomReadTime = totalRandomReadTime / (float)numOperations;
            Serial.printf("平均随机读取时间: %.2f ms/4KB\n", avgRandomReadTime);
        }

        // 清理
        SD_MMC.remove(testFile);
        free(buffer);
    }
    Serial.println("----------------------------------------");

    // 只需调用 usbMsc.begin，是否挂载由库内部自动判断
    usbMsc.setMountTimeout(3000);  // 设置3秒超时
    usbMsc.setFastMountFlag(true); // 启用快速挂载
    usbMsc.begin(&SD_MMC);

    // 注册 USB 事件回调
    usbMsc.registerUsbEventCallback(myUsbEventHandler);

    // 在 setup() 函数中添加回调注册
    usbMsc.registerMountCallback(myMountHandler);

    // 初始化 OneButton 按键
    button.attachClick(toggleUsbMsc);
    Serial.println("Setup completed");
}

void loop()
{
    button.tick(); // 轮询按键

    // 检查是否需要执行文件测试
    if (needFileTest && (millis() - lastUnmountTime >= UNMOUNT_DELAY))
    {
        needFileTest = false; // 清除标志
        testFileOperations(); // 执行文件测试
    }
}